package cn.tedu.tmall.front.account.filter;

import cn.tedu.tmall.common.enumerator.ServiceCode;
import cn.tedu.tmall.common.pojo.authentication.CurrentPrincipal;
import cn.tedu.tmall.common.pojo.po.UserStatePO;
import cn.tedu.tmall.common.web.JsonResult;
import cn.tedu.tmall.front.account.dao.cache.IUserCacheRepository;
import com.alibaba.fastjson.JSON;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.MalformedJwtException;
import io.jsonwebtoken.SignatureException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;


// 解析JWT的过滤器，主要负责：
// 1. 尝试接收客户端携带的JWT
// 2. 尝试解析客户端携带的JWT
// 3. 将解析成功后得到的用户数据（id, username）用于创建Authentication对象，并存入到SecurityContext中
@Component
public class JwtAuthorizationFilter extends OncePerRequestFilter {
    @Autowired
    private IUserCacheRepository userCacheRepository;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        System.out.println("JwtAuthorizationFilter.doFilterInternal对请求进行过滤：" + request.getRequestURI());

        // 尝试接收客户端携带的JWT
        // 根据业内的惯例，JWT数据应该是请求头中名为Authorization的属性
        String jwt = request.getHeader("Authorization");
        System.out.println("-------------------" + jwt);

        //检查JWT的基本有效性
        if (jwt == null) {
            // 对于无效的JWT，应该直接放行
            filterChain.doFilter(request, response);
            return;
        }

        //解析jwt
        String secretKey = "sdasdawdhajsdia/..(*8923-02";
        Claims claims = null;
        response.setContentType("application/json; charset=utf-8");
        try {
            claims= Jwts.parser()
                    .setSigningKey(secretKey)
                    .parseClaimsJws(jwt)
                    .getBody();
        }catch (SignatureException e){
            // jwt签名有错
            String message = "滚,非法访问！[1]";
            JsonResult jsonResult = JsonResult.fail(
                    ServiceCode.ERR_JWT_SIGNATURE, message
            );
            String jsonString = JSON.toJSONString(jsonResult);
            PrintWriter writer = response.getWriter();
            writer.println(jsonString);
            return;
        }catch (MalformedJwtException e){
            // jwt格式错误
            String message = "滚,非法访问！[2]";
            JsonResult jsonResult = JsonResult.fail(
                    ServiceCode.ERR_JWT_MALFORMED, message
            );
            String jsonString = JSON.toJSONString(jsonResult);
            PrintWriter writer = response.getWriter();
            writer.println(jsonString);
            return;
        }catch (Throwable e){
            String message = "服务器繁忙,请请稍后再试！【在开发过程中，如果看到此提示，你应该在服务器端的控制台观察异常的跟踪信息，并且，在解析JWT的过滤器中添加处理此异常的方法】";
            JsonResult jsonResult = JsonResult.fail(
                    ServiceCode.ERROR_UNKNOWN, message
            );
            String jsonString = JSON.toJSONString(jsonResult);
            PrintWriter writer = response.getWriter();
            writer.println(jsonString);
            return;
        }

        // 从JWT中获取用户数据
        Long userId = claims.get("id", Long.class);
        String username = claims.get("username", String.class);
        String remoteAddr=claims.get("remoteAddr",String.class);
        String userAgent=claims.get("userAgent",String.class);

        // 检查JWT是否存在被盗用的问题
        String currentRemoteAddr = request.getRemoteAddr();// IP地址
        String currentUserAgent = request.getHeader("User-Agent");// 浏览器信息
        if (!currentRemoteAddr.equals(remoteAddr) && !currentUserAgent.equals(userAgent)){
            filterChain.doFilter(request,response);
            return;
        }

        // 从缓存中读取用户登录信息
        UserStatePO userState = userCacheRepository.getUserState(userId);
        if (userState == null) {
            filterChain.doFilter(request, response);
            return;
        }

        // 检查账号状态
        Integer enable = userState.getEnable();// 获取用户的enable的值
        if (enable==0){
            String message = "操作失败,你的账号被禁用了";
            JsonResult jsonResult = JsonResult.fail(
                    ServiceCode.ERROR_UNAUTHORIZED_DISABLED, message
            );
            String jsonString = JSON.toJSONString(jsonResult);
            PrintWriter writer = response.getWriter();
            writer.println(jsonString);
            // 账号被禁用,在redis里面删除账号
            userCacheRepository.deleteUserState(userId);
            return;
        }

        // 添加用户的真实权限
        String authoritiesJsonString = userState.getAuthoritiesJsonString();
        List<String> permissions = JSON.parseArray(authoritiesJsonString, String.class);

        //准备权限列表
        ArrayList<SimpleGrantedAuthority> authorities = new ArrayList<>();
        for (String permission : permissions) {
            SimpleGrantedAuthority authority = new SimpleGrantedAuthority(permission);
            authorities.add(authority);
        }

        // 将解析成功后得到的用户数据（id, username）用于创建当事人对象
        CurrentPrincipal principal = new CurrentPrincipal();
        principal.setId(userId);
        principal.setUsername(username);

        //将当事人与权限列表用于创建Authentication对象
        Authentication authentication = new UsernamePasswordAuthenticationToken(
                principal, null, authorities);

        //将Authentication对象存入到SecurityContext中
        SecurityContext securityContext = SecurityContextHolder.getContext();
        securityContext.setAuthentication(authentication);

        // 登录成功设置时效性
        userCacheRepository.renewal(userId);

        // 放行（过滤器链继续向后传递，即：下一个过滤器将执行，如果已经是最后一个过滤器，则会把请求交给控制器进行处理）
        filterChain.doFilter(request, response);
    }
}
